#pragma once
#include<iostream>
#include<string>
#include<pthread.h>
#include <stdio.h>
#include<unistd.h>
#include <functional>
#include<cassert>

// 首先我们需要什么 ， 名字 ，id ，需要的执行的函数, 还有线程属性可以包括线程的堆栈大小、调度策略、分离状态等。

// class Thread;

//上下文,当成一个大号的结构体
// class Context
// {
//     typedef std::function<void*(void*)> func_t;
// public:
//     Thread *_this;
//     void *_args;
//     func_t func;
// public:
//     Context():_this(nullptr), _args(nullptr),_func(nullptr)
//     {}
//     ~Context()
//     {}
// };


class Thread
{
private:
    static void* start_routine(void*args)
    {
        Thread* _this = static_cast<Thread*>(args);
        // Context *ctx = static_cast<Context *>(args);
        // void *ret = ctx->_this->_func();
        // delete ctx;
        // return ret;
        return _this->callback();
    }
public:
    // 这里就是申明了一种函数类型
    typedef std::function<void*(void*)> func_t;
    const int num = 1024;
public:
    Thread()
    {
        char buffer[num];
        snprintf(buffer, sizeof buffer,"thread-%d",threadnum++);
        _name = buffer;
    }

    void join()
    {
        int n = pthread_join(_tid, nullptr);
        assert(n == 0);
        (void)n;
    }

    void start(func_t func,void *args=nullptr)
    {
        // Context* ctx = new Context();
        // ctx->_this=this;
        // ctx->_args =_args;
        _func =func;
        _args =args;
        int n = pthread_create(&_tid, nullptr, start_routine, this);
        assert(n == 0); //编译debug的方式发布的时候存在，release方式发布，assert就不存在了，n就是一个定义了，但是没有被使用的变量
        // 在有些编译器下会有warning
        (void)n;
    }

    std::string threadname()
    {
        return _name;
    }
     void *callback() 
    { 
        return _func(_args);
    }

    ~Thread()
    {
        // do nothing
    }
private:
    std::string _name; // 线程名字
    pthread_t _tid;   // 线程id
    void* _args; // 这个其实是pthread_create 函数的const pthread_attr_t attr属性 。             // 如果传入 NULL，线程将使用默认属性创建。线程属性可以包括线程的堆栈大小、调度策略、分离状态等。
    func_t _func; // 执行的任务函数
    static int threadnum;
};
 int Thread::threadnum = 1;